package yc.gg.service.Impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import yc.gg.constants.RedisConstants;
import yc.gg.domain.po.User;
import yc.gg.domain.req.LoginReq;
import yc.gg.domain.req.MessageReq;
import yc.gg.domain.req.PhoneEncryptReq;
import yc.gg.mapper.UserMapper;
import yc.gg.service.IUserService;
import yc.gg.utils.*;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static yc.gg.constants.RedisConstants.*;

/**
 * \* User: Fuyue
 * \* Date: 2025/5/19
 * \* Description:
 * \
 */
@Service
@Slf4j
public class UserServiceImpl implements IUserService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private UserMapper userMapper;

    @Override
    public Result login(LoginReq wxLoginReq) {
        try {
            // 参数校验
            if (wxLoginReq == null || StringUtils.isBlank(wxLoginReq.getCode())) {
                return Result.error("非法请求");
            }

            // 微信认证
            JSONObject wechatAuth = WechatUtils.getSessionKeyOrOpenId(wxLoginReq.getCode());
            JsonNode node = new ObjectMapper().readTree(wechatAuth.toString());

            if (node.has("errcode")) {
                log.error("微信认证失败: {}", node);
                return Result.error(String.valueOf(node));
            }

            String openid = node.get("openid").asText();
            String sessionKey = node.get("session_key").asText();

            // 查询或创建用户
            User user = userMapper.findByOpenId(openid);

            if (user == null) {
//                String userId = IdUtil.getSnowflakeNextIdStr();
                user = User.builder()
//                        .userId(userId)
                        .openId(openid)
                        .build();
                userMapper.save(user);
            }

            String token = JwtUtils.generateToken(user.getOpenId());

            String tokenKey = LOGIN_USER_KEY + token;
            Map<String,String> userData = new HashMap<>();
//            userData.put("userId", user.getUserId());
            userData.put("openid",openid);
            userData.put("sessionKey",sessionKey);
            userData.put("token",token);

            stringRedisTemplate.opsForHash().putAll(tokenKey, userData);
            stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);

            return Result.success(token);

        } catch (JsonProcessingException e) {
            log.error("JSON解析异常: {}", e.getMessage());
            return Result.error("系统错误");
        } catch (Exception e) {
            log.error("登录系统异常: {}", e.getMessage());
            return Result.error("系统错误");
        }
    }

    @Override
    public Result getPhone(String token, PhoneEncryptReq data) throws Exception {
        try{
            String tokenKey = RedisConstants.LOGIN_USER_KEY + token;
            String sessionKey = (String) stringRedisTemplate.opsForHash().get(tokenKey, "sessionKey");

            if (sessionKey == null) {
                return Result.error("会话已过期，请重新登录");
            }

            String phone = WechatUtils.decryptPhoneNumber(sessionKey, data.getEncryptedData(), data.getIv());
            String encrypt = Md5Util.getMD5String(phone);

            String openid = (String) stringRedisTemplate.opsForHash().get(tokenKey, "openid");
            log.info("用户id:{}的手机号为{}",openid,phone);
            userMapper.updateUserPhone(openid, encrypt);

            return Result.success(encrypt);
        }
         catch (Exception e) {
            log.error("解密手机号失败: {}", e.getMessage());
            return Result.error("解密失败");
        }
    }

    @Override
    public Result message(MessageReq messageReq) {
        String openid = UserHolder.getUser().getOpenid();
        String icon = messageReq.getIcon();
        String name = messageReq.getName();
        if(icon != null && name != null){
            userMapper.message(icon,name,openid);
            return Result.success("保存成功");
        }
        return Result.error("头像或者名称为空");
    }

    @Override
    public Result getMessage() {
        String openid = UserHolder.getUser().getOpenid();
        User u = userMapper.findByOpenId(openid);
        return Result.success(u);
    }

    @Override
    public Result sign() {
        String userId = UserHolder.getUser().getOpenid();
        LocalDateTime now = LocalDateTime.now();

        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = USER_SIGN_KEY + userId + keySuffix;
        String continuousKey = USER_SIGN_CONTINUOUS_KEY + userId;

        // 获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();

        // 若已经签到
        Boolean isSigned = stringRedisTemplate.opsForValue().getBit(key, dayOfMonth - 1);
        if (Boolean.TRUE.equals(isSigned)) {
            return Result.success("已签到");
        }

        // 检查昨天是否签到，更新连续签到天数
        Boolean isSignedYesterday = false;
        if (dayOfMonth > 1) {
            isSignedYesterday = stringRedisTemplate.opsForValue().getBit(key, dayOfMonth - 2);
        }

        // 未签到,则签到
        stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);

        // 更新连续签到天数
        int continuousDays = 1;
        if (isSignedYesterday) {
            //获取并增加连续签到天数
            String continuousDaysStr = stringRedisTemplate.opsForValue().get(continuousKey);
            if (StringUtils.isNotEmpty(continuousDaysStr)) {
                continuousDays = Integer.parseInt(continuousDaysStr) + 1;
            }
        } else {
            //重置连续签到天数
            continuousDays = 1;
        }
        stringRedisTemplate.opsForValue().set(continuousKey, String.valueOf(continuousDays));
        return Result.success("签到成功");
    }

    @Override
    public Result signCount() {
        String userId = UserHolder.getUser().getOpenid();
        // 获取日期
        LocalDateTime now = LocalDateTime.now();
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = "sign:" + userId + keySuffix;
        int dayOfMonth = now.getDayOfMonth();

        // 获取本月截止今天为止的所有的签到记录
        List<Long> result = stringRedisTemplate.opsForValue().bitField(
                key,
                BitFieldSubCommands.create()
                        .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0)
        );
        if (result == null || result.isEmpty()) {
            // 没有任何签到结果
            return Result.success(0);
        }
        Long num = result.get(0);
        if (num == null || num == 0) {
            return Result.success(0);
        }

        HashMap<String, Object> hashMap = new HashMap<>();

        // 本月签到记录
        List<Boolean> signRecord = new ArrayList<>();

        int count = 0;
        int daysInMonth = now.getMonth().length(now.toLocalDate().isLeapYear());
        for (int day = 1; day <= daysInMonth; day++) {
            Boolean signed = stringRedisTemplate.opsForValue().getBit(key, day - 1);
            if (Boolean.TRUE.equals(signed)) {
                count++;
            }
            signRecord.add(signed);
        }
        hashMap.put("signInCount", String.valueOf(count));
        hashMap.put("signInList", signRecord);

        return Result.success(hashMap);
    }

    public Result checkSignStatus() {
        String userId = UserHolder.getUser().getOpenid();
        LocalDateTime now = LocalDateTime.now();
        int dayOfMonth = now.getDayOfMonth();

        // 构建 Redis 键
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String signKey = USER_SIGN_KEY + userId + keySuffix;

        // 检查今天是否已签到
        Boolean isSigned = stringRedisTemplate.opsForValue().getBit(signKey, dayOfMonth - 1);
        // 返回签到状态
        Map<String, Object> result = new HashMap<>();
        result.put("isSigned", Boolean.TRUE.equals(isSigned));

        // 获取连续签到天数
        String continuousKey = USER_SIGN_CONTINUOUS_KEY + userId;
        String continuousDaysStr = stringRedisTemplate.opsForValue().get(continuousKey);
        result.put("continuousDays", StringUtils.isNotEmpty(continuousDaysStr)
                ? Integer.parseInt(continuousDaysStr)
                : 0);

        return Result.success(result);
    }

}
